﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.IO;
using System.Configuration;
using Microsoft.Practices.Unity.Configuration;

namespace YasharEl.Infrastructure.ObjectFactory.Unity.Configuration
{
    internal class UnityLoader
    {
        internal void Load(IUnityContainer unityContainer, System.Configuration.Configuration config)
        {
            Contract.Requires<ArgumentNullException>(unityContainer != null,
                "UnityLoader must load dependencies to [unityContainer]. Please provide [unityContainer] as parameter to the Load method.");
            Contract.Requires<ArgumentNullException>(config != null, "unityConfig could not be null.");

            UnityConfig unityConfig = config.GetSection(UnityConfig.UnityConfigSectionName) as UnityConfig;
            if (unityConfig != null &&
                unityConfig.Locations != null &&
                unityConfig.Locations.Count > 0)
            {
                try
                {
                    foreach (UnityLocationConfig unityLocation in unityConfig.Locations)
                    {
                        Configure(unityContainer, unityLocation);
                    }
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }

        private void Configure(IUnityContainer unityContainer, UnityLocationConfig location)
        {
            Contract.Requires<ArgumentNullException>(unityContainer != null, "unityContainer could not be null.");
            Contract.Requires<ArgumentNullException>(location != null, "location could not be null.");
            Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(location.Path), "location.Path could not be null or empty.");

            ExeConfigurationFileMap map = new ExeConfigurationFileMap();
            map.ExeConfigFilename = Path.Combine(Path.GetDirectoryName(
                Assembly.GetExecutingAssembly().Location), location.Path);
            if (!File.Exists(map.ExeConfigFilename))
            {
                map.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, location.Path);
                if (!File.Exists(map.ExeConfigFilename))
                {
                    throw new DependencyContainerConfigurationException("Unity configuration file was not found under the following location: " + map.ExeConfigFilename);
                }
            }
            System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

            if (!config.HasFile)
                throw new DependencyContainerConfigurationException("Unity configuration file was not found under the following location: " + map.ExeConfigFilename);

            UnityConfigurationSection unitySection = (UnityConfigurationSection)config.GetSection(UnityConfigurationSection.SectionName);
            if (string.IsNullOrWhiteSpace(location.ContainerName))
            {
                UnityConfigurationSection.CurrentSection.Configure(unityContainer);
            }
            else
            {
                UnityConfigurationSection.CurrentSection.Configure(unityContainer, location.ContainerName);
            }
        }
    }
}
